package com.zx.flow.api.util;

import com.auth0.jwt.exceptions.JWTVerificationException;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import com.zx.flow.api.dict.FlowDict.Event;
import com.zx.flow.api.dict.FlowDict.OperatorRule;
import com.zx.flow.api.exception.FlowException;
import com.zx.flow.api.execute.model.FlowContext;
import com.zx.flow.api.execute.model.FlowNode;
import com.zx.flow.api.execute.model.FlowOperator;
import com.zx.flow.api.execute.response.FlowResult;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

public class AssertUtil {

    /**
     * 校验 nodeId是当前的node
     *
     * @param flow
     * @param nodeId
     */
    public static FlowNode checkCurrentNodeId(FlowContext flow, String nodeId) {
        FlowNode currentNode = checkCurrentNodeNotNull(flow);
        if (!Objects.equals(currentNode.getId(), nodeId)) {
            throw new FlowException("不是当前节点, nodeId=" + nodeId + ", currNodeId=" + currentNode.getId());
        }
        return currentNode;
    }

    public static void checkNodeNotNull(FlowNode node) {
        checkNotNull(node, "节点不存在");
    }

    public static void throwFE(String msg) {
        throw new FlowException(msg);
    }

    public static void checkFlowNotNull(FlowContext flow, String flowId) {
        checkNotNull(flow, "流程不存在, flowId=" + flowId);
    }

    public static void checkApplyAccount(FlowContext flow, String accountCode) {
        checkEques(flow.getApplyAccountCode(), accountCode,
                "申请人应该是" + flow.getApplyAccountCode() + ", 而不是" + accountCode);
    }

    public static FlowNode checkCurrentNodeNotNull(FlowContext flow) {
        FlowNode current = FlowDataUtil.getCurrent(flow);
        checkNodeNotNull(current);
        return current;
    }

    public static void checkNotNull(Object object, String msg) {
        if (object == null) {
            throw new FlowException(msg);
        }
    }

    public static void checkNotSystem(FlowOperator operator) {
        if (!OperatorsUtil.checkSystem(operator)) {
            throw new FlowException("只允许[系统账号]或者[系统权限]操作");
        }
    }

    public static void checkNotSystem(String accountCode) {
        if (!OperatorsUtil.checkSystem(accountCode)) {
            throw new FlowException("只允许[系统账号]操作");
        }
    }

    public static void checkNotEmpty(List<?> list, String msg) {
        if (CollectionUtils.isEmpty(list)) {
            throw new FlowException(msg);
        }
    }

    public static void checkFlowResult(FlowResult result) {
        if (result == null || !result.isOk()) {
            throw new FlowException(result.toString());
        }
    }

    /**
     * 校验操作人权限
     *
     * @param node
     * @param accountCode
     * @param rules
     */
    public static void checkOperator(FlowNode node, String accountCode, OperatorRule... rules) {
        // 系统操作，不需要校验
        if (OperatorsUtil.checkSystem(accountCode)) {
            return;
        }
        List<FlowOperator> operators = node.getOperators();
        if (CollectionUtils.isEmpty(operators)) {
            throw new FlowException("操作人列表为空, accountCode=" + accountCode);
        }
        FlowOperator findOperator = OperatorsUtil.find(operators, accountCode);
        if (findOperator == null) {
            throw new FlowException("操作人列表没有此人, accountCode=" + accountCode);
        }
        for (OperatorRule rule : rules) {
            if (Objects.equals(findOperator.getRule(), rule.getCode())) {
                return;
            }
        }
        throw new FlowException("没有操作人权限, accountCode=" + accountCode);
    }

    public static void checkOperator(FlowContext flow, String nodeId, String accountCode) {
        checkOperator(flow, nodeId, accountCode, OperatorRule.operator);
    }

    public static void checkOperator(FlowContext flow, String nodeId, String accountCode, OperatorRule... rules) {
        FlowNode currNode = AssertUtil.checkCurrentNodeId(flow, nodeId);
        checkOperator(currNode, accountCode, rules);
    }

    /**
     * 校验操作权限
     *
     * @param node
     * @param accountCode
     */
    public static void checkOperator(FlowNode node, String accountCode) {
        checkOperator(node, accountCode, OperatorRule.operator);
    }

    /**
     * 校验事件，符合任意一个
     *
     * @param event
     * @param checkList
     */
    public static void checkEvent(String event, Event... checkList) {
        checkNotNull(checkList, "校验事件列表不能为空");
        boolean bool = event(event, checkList);
        if (bool) {
            throw new FlowException("校验事件失败, checkList=" + checkList.toString() + ", event=" + event);
        }
    }

    public static boolean event(String event, Event... checkList) {
        for (Event check : checkList) {
            if (Objects.equals(event, check.getCode())) {
                return true;
            }
        }
        return false;
    }


    /**
     * 两个集合不能有交集【类必须实现equals hashCode 方法】
     *
     * @param a
     * @param b
     */
    public static void checkNotIntersection(List<?> a, List<?> b, String msg) {
        SetView<?> view = Sets.intersection(Sets.newHashSet(a), Sets.newHashSet(b));
        if (view.isEmpty()) {
            throw new FlowException(msg);
        }
    }

    /**
     * 校验sub是否为all的子集
     *
     * @param all
     * @param sub
     * @param msg
     */
    public static void checkNotContains(List<?> all, List<?> sub, String msg) {
        for (Object s : sub) {
            if (!all.contains(s)) {
                throw new FlowException(msg);
            }
        }
    }

    public static void checkEques(Object o1, Object o2, String msg) {
        if (!Objects.equals(o1, o2)) {
            throw new FlowException(msg);
        }
    }

    public static void checkNotIntersection(List<?> a, List<?> b) {
        checkNotIntersection(a, b, "两个集合不能有交集");
    }


    public static void checkSecurity(Object info, String msg) {
        if (info instanceof String) {
            if (StringUtils.isEmpty(info)) {
                throw new JWTVerificationException(msg);
            }
        } else if (info instanceof Collection) {
            if (CollectionUtils.isEmpty((Collection) info)) {
                throw new JWTVerificationException(msg);
            }
        } else if (info instanceof Map) {
            if (CollectionUtils.isEmpty((Map) info)) {
                throw new JWTVerificationException(msg);
            }
        } else if (info == null) {
            throw new JWTVerificationException(msg);
        }
    }
}
